{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "SzKwuqYESWwm"
   },
   "source": [
    "##### Copyright 2021 The Cirq Developers"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "cellView": "form",
    "id": "4yPUsdJxSXFq"
   },
   "outputs": [],
   "source": [
    "# @title Licensed under the Apache License, Version 2.0 (the \"License\");\n",
    "# you may not use this file except in compliance with the License.\n",
    "# You may obtain a copy of the License at\n",
    "#\n",
    "# https://www.apache.org/licenses/LICENSE-2.0\n",
    "#\n",
    "# Unless required by applicable law or agreed to in writing, software\n",
    "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
    "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
    "# See the License for the specific language governing permissions and\n",
    "# limitations under the License."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "zC1qlUJoSXhm"
   },
   "source": [
    "<table class=\"tfo-notebook-buttons\" align=\"left\">\n",
    "  <td>\n",
    "    <a target=\"_blank\" href=\"https://quantumai.google/cirq/noise/qcvv/isolated_xeb\"><img src=\"https://quantumai.google/site-assets/images/buttons/quantumai_logo_1x.png\" />View on QuantumAI</a>\n",
    "  </td>\n",
    "  <td>\n",
    "    <a target=\"_blank\" href=\"https://colab.research.google.com/github/quantumlib/Cirq/blob/main/docs/noise/qcvv/isolated_xeb.ipynb\"><img src=\"https://quantumai.google/site-assets/images/buttons/colab_logo_1x.png\" />Run in Google Colab</a>\n",
    "  </td>\n",
    "  <td>\n",
    "    <a target=\"_blank\" href=\"https://github.com/quantumlib/Cirq/blob/main/docs/noise/qcvv/isolated_xeb.ipynb\"><img src=\"https://quantumai.google/site-assets/images/buttons/github_logo_1x.png\" />View source on GitHub</a>\n",
    "  </td>\n",
    "  <td>\n",
    "    <a href=\"https://storage.googleapis.com/tensorflow_docs/Cirq/docs/noise/qcvv/isolated_xeb.ipynb\"><img src=\"https://quantumai.google/site-assets/images/buttons/download_icon_1x.png\" />Download notebook</a>\n",
    "  </td>\n",
    "</table>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "bd9529db1c0b"
   },
   "outputs": [],
   "source": [
    "try:\n",
    "    import cirq\n",
    "except ImportError:\n",
    "    print(\"installing cirq...\")\n",
    "    !pip install --quiet cirq\n",
    "    print(\"installed cirq.\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "dd95be2a71eb"
   },
   "source": [
    "# Isolated XEB\n",
    "\n",
    "This notebook demonstrates how to use the functionality in `cirq.experiments` to run Isolated XEB end-to-end. \"Isolated\" means we do one pair of qubits at a time."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "046b07823210"
   },
   "outputs": [],
   "source": [
    "import cirq\n",
    "import numpy as np"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "ace31cc4d258"
   },
   "source": [
    "## Set up Random Circuits\n",
    "\n",
    "We create a library of 20 random, two-qubit `circuits` using the sqrt(ISWAP) gate on the two qubits we've chosen."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "03ad48eb554a"
   },
   "outputs": [],
   "source": [
    "from cirq.experiments import random_quantum_circuit_generation as rqcg\n",
    "\n",
    "circuits = rqcg.generate_library_of_2q_circuits(\n",
    "    n_library_circuits=20,\n",
    "    two_qubit_gate=cirq.ISWAP**0.5,\n",
    "    q0=cirq.GridQubit(4, 4),\n",
    "    q1=cirq.GridQubit(4, 5),\n",
    ")\n",
    "print(len(circuits))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "c7c044ec12ac"
   },
   "outputs": [],
   "source": [
    "# We will truncate to these lengths\n",
    "max_depth = 100\n",
    "cycle_depths = np.arange(3, max_depth, 20)\n",
    "cycle_depths"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "4bf3dbdfac5a"
   },
   "source": [
    "### Set up a `Sampler`.\n",
    "\n",
    "For demonstration, we'll use a density matrix simulator to sample noisy samples. However, input a `device_name` (and have an authenticated Google Cloud project name set as your `GOOGLE_CLOUD_PROJECT` environment variable) to run on a real device."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "f974bb59afb4"
   },
   "outputs": [],
   "source": [
    "device_name = None  # change me!\n",
    "\n",
    "if device_name is None:\n",
    "    sampler = cirq.DensityMatrixSimulator(noise=cirq.depolarize(5e-3))\n",
    "else:\n",
    "    import cirq_google as cg\n",
    "\n",
    "    sampler = cg.get_engine_sampler(device_name, gate_set_name='sqrt_iswap')\n",
    "    device = cg.get_engine_device(device_name)\n",
    "\n",
    "    import cirq.contrib.routing as ccr\n",
    "\n",
    "    graph = ccr.gridqubits_to_graph_device(device.qubits)\n",
    "    pos = {q: (q.row, q.col) for q in graph.nodes}\n",
    "    import networkx as nx\n",
    "\n",
    "    nx.draw_networkx(graph, pos=pos)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "bd50664b583a"
   },
   "source": [
    "## Take Data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "a1deda080b5b"
   },
   "outputs": [],
   "source": [
    "from cirq.experiments.xeb_sampling import sample_2q_xeb_circuits\n",
    "\n",
    "sampled_df = sample_2q_xeb_circuits(\n",
    "    sampler=sampler, circuits=circuits, cycle_depths=cycle_depths, repetitions=10_000\n",
    ")\n",
    "sampled_df"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "99b51deacbe4"
   },
   "source": [
    "## Benchmark fidelities"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "3896c772ad49"
   },
   "outputs": [],
   "source": [
    "from cirq.experiments.xeb_fitting import benchmark_2q_xeb_fidelities\n",
    "\n",
    "fids = benchmark_2q_xeb_fidelities(\n",
    "    sampled_df=sampled_df, circuits=circuits, cycle_depths=cycle_depths\n",
    ")\n",
    "fids"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "8c08c9ab8109"
   },
   "outputs": [],
   "source": [
    "%matplotlib inline\n",
    "from matplotlib import pyplot as plt\n",
    "\n",
    "# Exponential reference\n",
    "xx = np.linspace(0, fids['cycle_depth'].max())\n",
    "plt.plot(xx, (1 - 5e-3) ** (4 * xx), label=r'Exponential Reference')\n",
    "\n",
    "\n",
    "def _p(fids):\n",
    "    plt.plot(fids['cycle_depth'], fids['fidelity'], 'o-', label=fids.name)\n",
    "\n",
    "\n",
    "fids.name = 'Sampled'\n",
    "_p(fids)\n",
    "\n",
    "plt.ylabel('Circuit fidelity')\n",
    "plt.xlabel('Cycle Depth $d$')\n",
    "plt.legend(loc='best')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "9715be97ec17"
   },
   "source": [
    "## Optimize `PhasedFSimGate` parameters\n",
    "\n",
    "We know what circuits we requested, and in this simulated example, we know what coherent error has happened. But in a real experiment, there is likely unknown coherent error that you would like to characterize. Therefore, we make the five angles in `PhasedFSimGate` free parameters and use a classical optimizer to find which set of parameters best describes the data we collected from the noisy simulator (or device, if this was a real experiment)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "ed89fa788b84"
   },
   "outputs": [],
   "source": [
    "import multiprocessing\n",
    "\n",
    "pool = multiprocessing.get_context('spawn').Pool()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "33a7946b11f0"
   },
   "outputs": [],
   "source": [
    "from cirq.experiments.xeb_fitting import (\n",
    "    parameterize_circuit,\n",
    "    characterize_phased_fsim_parameters_with_xeb,\n",
    "    SqrtISwapXEBOptions,\n",
    ")\n",
    "\n",
    "# Set which angles we want to characterize (all)\n",
    "options = SqrtISwapXEBOptions(\n",
    "    characterize_theta=True,\n",
    "    characterize_zeta=True,\n",
    "    characterize_chi=True,\n",
    "    characterize_gamma=True,\n",
    "    characterize_phi=True,\n",
    ")\n",
    "# Parameterize the sqrt(iswap)s in our circuit library\n",
    "pcircuits = [parameterize_circuit(circuit, options) for circuit in circuits]\n",
    "\n",
    "# Run the characterization loop\n",
    "characterization_result = characterize_phased_fsim_parameters_with_xeb(\n",
    "    sampled_df,\n",
    "    pcircuits,\n",
    "    cycle_depths,\n",
    "    options,\n",
    "    pool=pool,\n",
    "    # ease tolerance so it converges faster:\n",
    "    fatol=5e-3,\n",
    "    xatol=5e-3,\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "fb24fa496cbe"
   },
   "outputs": [],
   "source": [
    "characterization_result.final_params"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "9845785f9a6a"
   },
   "outputs": [],
   "source": [
    "characterization_result.fidelities_df"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "55d1bc779f0f"
   },
   "outputs": [],
   "source": [
    "from cirq.experiments.xeb_fitting import before_and_after_characterization\n",
    "\n",
    "before_after_df = before_and_after_characterization(fids, characterization_result)\n",
    "before_after_df"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "39d3e22dc65a"
   },
   "outputs": [],
   "source": [
    "from cirq.experiments.xeb_fitting import exponential_decay\n",
    "\n",
    "for i, row in before_after_df.iterrows():\n",
    "    plt.axhline(1, color='grey', ls='--')\n",
    "    plt.plot(row['cycle_depths_0'], row['fidelities_0'], '*', color='red')\n",
    "    plt.plot(row['cycle_depths_c'], row['fidelities_c'], 'o', color='blue')\n",
    "\n",
    "    xx = np.linspace(0, np.max(row['cycle_depths_0']))\n",
    "    plt.plot(xx, exponential_decay(xx, a=row['a_0'], layer_fid=row['layer_fid_0']), color='red')\n",
    "    plt.plot(xx, exponential_decay(xx, a=row['a_c'], layer_fid=row['layer_fid_c']), color='blue')\n",
    "\n",
    "    plt.show()"
   ]
  }
 ],
 "metadata": {
  "colab": {
   "name": "isolated_xeb.ipynb",
   "toc_visible": true
  },
  "kernelspec": {
   "display_name": "Python 3",
   "name": "python3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
